package com.hyt.it.ogt.kq.service.gov.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hyt.common.apiInfor.ApiResponse;
import com.hyt.core.base.BaseServiceImpl;
import com.hyt.it.ogt.kq.common.config.exception.KqException;
import com.hyt.it.ogt.kq.common.enums.UserBusinessAccessTypeEnum;
import com.hyt.it.ogt.kq.common.gov.constant.CodeEnum;
import com.hyt.it.ogt.kq.common.gov.constant.ResponseCode;
import com.hyt.it.ogt.kq.common.gov.constant.UserRoleParam;
import com.hyt.it.ogt.kq.common.gov.constant.UserRoleType;
import com.hyt.it.ogt.kq.common.gov.enums.TreeNodeTypeEnum;
import com.hyt.it.ogt.kq.common.gov.utils.GovPage;
import com.hyt.it.ogt.kq.common.gov.utils.MathUtil;
import com.hyt.it.ogt.kq.service.gov.mapper.ExaminerMapper;
import com.hyt.it.ogt.kq.service.gov.model.dto.examiner.ExaminerRoomDTO;
import com.hyt.it.ogt.kq.service.gov.model.dto.examiner.OrgTreeParamDTO;
import com.hyt.it.ogt.kq.service.gov.model.dto.examiner.RoomExaminerDTO;
import com.hyt.it.ogt.kq.service.gov.model.entity.*;
import com.hyt.it.ogt.kq.service.gov.model.param.*;
import com.hyt.it.ogt.kq.service.gov.model.vo.examiner.KwExaminerVO;
import com.hyt.it.ogt.kq.service.gov.model.vo.examiner.TimeRoomExaminerVO;
import com.hyt.it.ogt.kq.service.gov.service.*;
import com.hyt.loginfo.model.OfficeUserVO;
import com.hyt.loginfo.model.Tree;
import com.hyt.loginfo.model.User;
import com.hyt.loginfo.model.UserVO;
import com.hyt.loginfo.model.param.OfficeUserPageParam;
import com.hyt.loginfo.model.param.QueryUsersParam;
import com.hyt.loginfo.model.param.SetUsersRoleIdsParam;
import com.hyt.loginfo.service.IUaDeptService;
import com.hyt.loginfo.service.IUaUserExtService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 考务人员表 服务实现类
 * </p>
 *
 * @author wangg
 * @since 2021-11-25
 */
@Slf4j
@Service
public class ExaminerServiceImpl extends BaseServiceImpl<ExaminerMapper, Examiner> implements IExaminerService {

    @Resource
    private ExaminerMapper examinerMapper;

    @Resource
    private IUaUserExtService iUaUserExtService;

    @Resource
    private IUaDeptService iUaDeptService;

    @Resource
    private ITimeExaminerService iTimeExaminerService;

    @Resource
    private ITimeRoomExaminerService iTimeRoomExaminerService;

    @Resource
    private ITimeRoomService iTimeRoomService;

    @Resource
    private ITaskService iTaskService;
    @Resource
    private IOfficeAreaService iOfficeAreaService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Tree> getKwExaminerOrgTree(String taskId, String timeId) {
        // 1：获取平台端全部部门
        ApiResponse<List<Tree>> responeObject = this.iUaDeptService.getKwDeptTree();
        if (!responeObject.getCode().equals(CodeEnum.UA_SUCCESS_CODE.getCode())) {
            throw new KqException(ResponseCode.ERROR_GET_POWER_USER.getCode(), "获取权限平台——查询部门树接口返回异常：" + responeObject.getCode());
        }
        List<Tree> treeList = responeObject.getData();
        // 2: 获取平台端全部用户，分页接口需要循环获取全部
        List<OfficeUserVO> deptUserList = getDeptUserList();
        // 3：通过timeId查询同一批次下的所有设置的考务人员
        List<TimeExaminer> timeExaminerList = iTimeExaminerService.getByTime(taskId, timeId, UserRoleType.USER_ROLE_TYPE_PROCTOR.getCode(), "");
        Set<String> userIdSet = timeExaminerList.stream().map(TimeExaminer::getUserId).collect(Collectors.toSet());
        // 4：组装全部数据
        // 4.1 标记之前保存设置的考务人员，用于标记前端回显
        deptUserList.stream().forEach(user -> {
            user.setStatus(false);
            if (userIdSet.contains(user.getId())) {
                user.setStatus(true);
            }
        });
        // 4.2 把平台查询的部门用户挂靠在对应的部门树中显示
        Map<String, List<OfficeUserVO>> officeUserVoGroupMap = deptUserList.stream().collect(Collectors.groupingBy(OfficeUserVO::getDeptId));
        getChildrenListTree(treeList, officeUserVoGroupMap);
        return treeList;
    }

    /**
     * @Description 获取平台端全部用户，需要循环获取用户数据（分页查询接口）
     * @Param
     * @Return List<OfficeUserVO>
     */
    private List<OfficeUserVO> getDeptUserList() {
        OfficeUserPageParam officeUserPageParam = new OfficeUserPageParam();
        int pageSize = 50;
        int pageNo = 1;

        List<OfficeUserVO> deptUserList = new ArrayList<>();
        while (true) {
            officeUserPageParam.setStatus(true);
            officeUserPageParam.setCurrent(pageNo);
            officeUserPageParam.setSize(pageSize);
            ApiResponse<Page<OfficeUserVO>> responseObject = iUaDeptService.getKwOfficeUserPage(officeUserPageParam);
            // 12001：成功；12281：查询机构用户分页异常; 12282：获取不到当前登录人信息;12283：当前查询的部门没有权限
            if (null == responseObject) {
                throw new KqException(ResponseCode.ERROR_GET_POWER_USER.getCode(), "获取权限平台——查询机构用户分页数据接口返回异常");
            }
            if (!CodeEnum.UA_SUCCESS_CODE.getCode().equals(responseObject.getCode()) && !CodeEnum.UA_SUCCESS_CODE_V2.getCode().equals(responseObject.getCode())) {
                throw new KqException(ResponseCode.ERROR_GET_POWER_USER.getCode(), "获取权限平台——查询机构用户分页数据接口返回异常");
            }
            if (null != responseObject.getData() && CollUtil.isNotEmpty(responseObject.getData().getRecords())) {
                List<OfficeUserVO> deptUserListTemp = responseObject.getData().getRecords();
                deptUserList.addAll(deptUserListTemp);
                pageNo++;
            } else {
                break;
            }
        }
        deptUserList.sort(Comparator.comparing(OfficeUserVO::getId));
        return deptUserList;
    }

    /**
     * @Description 组装全部部门和人员树结构数据（递归）
     * @Param
     * @Return
     */
    private void getChildrenListTree(List<Tree> treeList, Map<String, List<OfficeUserVO>> officeUserVoGroupMap) {
        treeList.stream().forEach(tree -> {
            String treeId = tree.getId();
            List<OfficeUserVO> officeUsers = officeUserVoGroupMap.get(treeId);
            if (!Objects.isNull(tree.getChildren())) {
                if (!Objects.isNull(officeUsers)) {
                    Set<Tree> userSet = saveUserToTreeSet(officeUsers);
                    List<Tree> listTemp = userSet.stream().collect(Collectors.toList());
                    listTemp.sort(Comparator.comparing(Tree::getId));
                    tree.getChildren().addAll(listTemp);
                } else {
                    ExaminerTreeNodeParam examinerTreeParam = new ExaminerTreeNodeParam();
                    examinerTreeParam.setIsUserOrDept(TreeNodeTypeEnum.TREE_NODE_TYPE_DEPT.getCode());
                    tree.getChildren().stream().forEach(children -> {
                        children.setObj(examinerTreeParam);
                    });
                }
                this.getChildrenListTree(tree.getChildren(), officeUserVoGroupMap);
            } else {
                if (!Objects.isNull(officeUsers)) {
                    Set<Tree> userSet = saveUserToTreeSet(officeUsers);
                    List<Tree> listTemp = userSet.stream().collect(Collectors.toList());
                    listTemp.sort(Comparator.comparing(Tree::getId));
                    tree.setChildren(listTemp);
                }
            }
        });
    }

    /**
     * @Description 组装用户属性信息到树结构
     * @Param
     * @Return
     */
    private Set<Tree> saveUserToTreeSet(List<OfficeUserVO> officeUsers) {
        Set<Tree> set = officeUsers.stream().map(officeUser -> {
            Tree treeTemp = new Tree();
            treeTemp.setId(officeUser.getId());
            treeTemp.setPid(officeUser.getDeptId());
            treeTemp.setText(officeUser.getName());
            ExaminerTreeNodeParam examinerTreeParam = new ExaminerTreeNodeParam();
            examinerTreeParam.setIsUserOrDept(TreeNodeTypeEnum.TREE_NODE_TYPE_USER.getCode());
            examinerTreeParam.setShow(officeUser.getStatus());
            treeTemp.setObj(examinerTreeParam);
            return treeTemp;
        }).collect(Collectors.toSet());
        return set;
    }

    @Override
    public List<OfficeUserVO> getOfficeUserPageSet(String taskId, String timeId, String deptId) {
        List<OfficeUserVO> officeUserVOS = getDeptUserList();
        return officeUserVOS;
    }

    @Override
    public Page<TimeRoomExaminerVO> getKwExaminerList(TimeRoomExaminerParam timeRoomExaminerParam) {
        // 1：查询批次考务人员和考场信息数据
        Page<TimeRoomExaminerVO> timeRoomExaminerListPage = examinerMapper.getTimeRoomExaminerList(timeRoomExaminerParam);
        List<TimeRoomExaminerVO> timeRoomExaminerList = timeRoomExaminerListPage.getRecords();
        if (CollUtil.isNotEmpty(timeRoomExaminerList)) {
            Set<String> userIds = timeRoomExaminerList.stream().map(TimeRoomExaminerVO::getUserId).collect(Collectors.toSet());
            // 2：根据List<String userId>获取用户信息列表，调用平台端接口
            QueryUsersParam params = new QueryUsersParam();
            params.setUserids(userIds.stream().collect(Collectors.toList()));
            ApiResponse<List<UserVO>> responseObject = this.iUaUserExtService.getUsersByIds(params);
            if (!responseObject.getCode().equals(CodeEnum.UA_SUCCESS_CODE.getCode())) {
                throw new KqException(ResponseCode.ERROR_GET_POWER_USER.getCode(), "获取权限平台——批量查询用户信息接口返回异常：" + responseObject.getCode());
            }
            List<UserVO> userVOList = responseObject.getData();
            // 3：进行数据组装
            timeRoomExaminerList.stream().forEach(timeRoomExaminerVO -> {
                userVOList.stream().forEach(userVO -> {
                    if (userVO.getUserid().equals(timeRoomExaminerVO.getUserId())) {
                        timeRoomExaminerVO.setExaminerName(userVO.getUsername());
                        timeRoomExaminerVO.setExaminerPhone(userVO.getPhone());
                        timeRoomExaminerVO.setProvince(userVO.getProvince());
                        timeRoomExaminerVO.setCity(userVO.getCity());
                        timeRoomExaminerVO.setDistrict(userVO.getDistrict());
                        timeRoomExaminerVO.setOrgName(userVO.getOrgName());
                        timeRoomExaminerVO.setAreaName(userVO.getAreaName());
                    }
                });
            });
            String searchWord = timeRoomExaminerParam.getSearchWord();
            if (!StringUtils.isEmpty(searchWord)) {
                timeRoomExaminerList = timeRoomExaminerList.stream().filter(tre ->
                        tre.getExaminerName().contains(searchWord) || tre.getExaminerPhone().contains(searchWord)
                ).collect(Collectors.toList());
                timeRoomExaminerListPage.setRecords(timeRoomExaminerList);
            }
        }
        return timeRoomExaminerListPage;
    }

    /**
     * 获取考务人员信息列表
     *
     * @param pageParam
     * @param timeRoomExaminerParam
     * @return 获取考务人员信息列表
     */
    @Override
    public Page<TimeRoomExaminerVO> getKwExaminerListV2(GovPage<KwExaminerVO> pageParam, TimeRoomExaminerParam timeRoomExaminerParam) {
        Page<TimeRoomExaminerVO> timeRoomExaminerListPage = examinerMapper.getTimeRoomExaminerListV2(pageParam, timeRoomExaminerParam);
        List<TimeRoomExaminerVO> timeRoomExaminerList = timeRoomExaminerListPage.getRecords();
        if (CollUtil.isNotEmpty(timeRoomExaminerList)) {
            Set<String> userIds = timeRoomExaminerList.stream().map(TimeRoomExaminerVO::getUserId).collect(Collectors.toSet());
            // 2：根据List<String userId>获取用户信息列表，调用平台端接口
            QueryUsersParam params = new QueryUsersParam();
            params.setUserids(new ArrayList<>(userIds));
            ApiResponse<List<UserVO>> responseObject = this.iUaUserExtService.getKwUsersByIds(params);
            log.info("从平台获取机构监考员信息返回为:【{}】",responseObject);
            if (!responseObject.getCode().equals(CodeEnum.UA_SUCCESS_CODE.getCode())) {
                throw new KqException(ResponseCode.ERROR_GET_POWER_USER.getCode(), "获取权限平台——批量查询用户信息接口返回异常：" + responseObject.getCode());
            }
            List<UserVO> userVOList = responseObject.getData();
            //处理机构名
            List<String> orgIds = timeRoomExaminerList.stream().filter(e -> StringUtils.isNotBlank(e.getOrganizationid()))
                    .map(TimeRoomExaminerVO::getOrganizationid).collect(Collectors.toList());
            Map<String, String> ancestorsNames = new HashMap<>();
            if(orgIds.size() > 0) {
                ancestorsNames.putAll(iUaDeptService.getAncestorsNames(orgIds));
            }
            Map<String, String> allAreaMap = getAllAreaMap();
            // 4：进行数据组装
            timeRoomExaminerList.stream().forEach(timeRoomExaminerVO -> {
                userVOList.stream().forEach(userVO -> {
                    if (userVO.getUserid().equals(timeRoomExaminerVO.getUserId())) {
                        timeRoomExaminerVO.setExaminerName(timeRoomExaminerVO.getExaminerName());
                        timeRoomExaminerVO.setExaminerPhone(userVO.getPhone());
                        timeRoomExaminerVO.setProvince(timeRoomExaminerVO.getProvince());
                        timeRoomExaminerVO.setCity(timeRoomExaminerVO.getCity());
                        timeRoomExaminerVO.setDistrict(timeRoomExaminerVO.getDistrict());
                        timeRoomExaminerVO.setOrganizationid(timeRoomExaminerVO.getOrganizationid());
                        //timeRoomExaminerVO.setOrgName(userVO.getOrgName());
                        //timeRoomExaminerVO.setAreaName(userVO.getAreaName());
                        if (StringUtils.isNotBlank(timeRoomExaminerVO.getOrganizationid())) {
                            timeRoomExaminerVO.setOrgName(ancestorsNames.get(timeRoomExaminerVO.getOrganizationid()));
                        }
                        timeRoomExaminerVO.setAreaName(joinAreaName(timeRoomExaminerVO.getProvince(), timeRoomExaminerVO.getCity(),
                                timeRoomExaminerVO.getDistrict(), allAreaMap));
                    }
                });
            });
        }
        return timeRoomExaminerListPage;
    }

    //获取平台的区域map key = id value = object
    private Map<String, String> getAllAreaMap() {
        List<TaskArea> allAreas = iOfficeAreaService.getAllAreaList();
        Map<String, String> map = allAreas.stream().collect(Collectors.toMap(TaskArea::getAreaId, TaskArea::getName, (k1, k2) -> k1));
        return map;
    }

    //拼接区域名称
    private String joinAreaName(String province, String city, String district, Map<String, String> mapTaskCandidateArea) {
        // 查询考生区域信息
        StringBuilder sb = new StringBuilder();
        if (org.apache.commons.lang3.StringUtils.isNotBlank(province)) {
            sb.append(mapTaskCandidateArea.get(province)).append("/");
        }
        if (org.apache.commons.lang3.StringUtils.isNotBlank(city)) {
            sb.append(mapTaskCandidateArea.get(city)).append("/");
        }
        if (org.apache.commons.lang3.StringUtils.isNotBlank(district)) {
            sb.append(mapTaskCandidateArea.get(district));
        }
        String area = sb.toString();
        log.info("接近的省市区是：【{}】",sb);
        if (org.apache.commons.lang3.StringUtils.isNotBlank(area) && area.length() == (area.lastIndexOf("/") + 1)) {
            area = area.substring(0, area.lastIndexOf("/"));
        }
        return area;
    }

    /**
     * 保存考务人员监考老师设置
     *
     * @param timeRoomExaminerParam
     * @param user
     * @return 保存考务人员监考老师 设置
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveKwExaminerListByTimeV2(TaskExaminerParam timeRoomExaminerParam, User user) {
        String taskId = timeRoomExaminerParam.getTaskId();
        // 0：判断编排数据是否锁定
        if (CollectionUtils.isEmpty(timeRoomExaminerParam.getUserIds())) {
            return;
        }
        //iTaskService.isNotLockDataThrowException(timeRoomExaminerParam.getTaskId());
        Set<String> newUserIdSet = new HashSet<>(timeRoomExaminerParam.getUserIds());
        // 1：考务人员基本信息kw_examiner表操作 考务和老师的关联
        List<Examiner> oldExaminerList = baseMapper.selectList(new LambdaQueryWrapper<Examiner>()
                .eq(Examiner::getTaskId, taskId).eq(Examiner::getDelFlag, Boolean.FALSE)
        );
        Set<String> oldUserIdSet = oldExaminerList.stream().map(Examiner::getUserId).collect(Collectors.toSet());
        // 差集
        Set<String> reduceUserIds = new HashSet<>();
        reduceUserIds.addAll(newUserIdSet);
        reduceUserIds.removeAll(oldUserIdSet);
        // 2：根据List<String userId>获取用户信息列表，调用平台端接口
        QueryUsersParam params = new QueryUsersParam();
        if (reduceUserIds.isEmpty()) {
            return;
        }
        params.setUserids(new ArrayList<>(reduceUserIds));
        ApiResponse<List<UserVO>> responseObject = this.iUaUserExtService.getUsersByIds(params);
        if (!responseObject.getCode().equals(CodeEnum.UA_SUCCESS_CODE.getCode())) {
            throw new KqException(ResponseCode.ERROR_GET_POWER_USER.getCode(), "获取权限平台——批量查询用户信息接口返回异常：" + responseObject.getCode());
        }
        List<UserVO> userVOList = responseObject.getData();

        // 批量添加kw_examiner表
        List<Examiner> examinerInsertList = new ArrayList<>();
        userVOList.stream().forEach(u -> {
            Examiner e = new Examiner();
            e.setTaskId(taskId);
            e.setUserName(u.getUsername());
            e.setUserId(u.getUserid());
            e.setType(UserRoleType.USER_ROLE_TYPE_PROCTOR.getCode());
            e.setDeptId(u.getOrganizationid());
            e.setOfficeId(u.getOfficeid());
            e.setProvince(u.getProvince());
            e.setCity(u.getCity());
            e.setDistrict(u.getDistrict());
            examinerInsertList.add(e);
        });
        if (CollUtil.isNotEmpty(examinerInsertList)) {
            saveBatch(examinerInsertList, examinerInsertList.size());
        }
        iTaskService.saveTaskBusinessAccess(user,taskId,new ArrayList<>(reduceUserIds), UserBusinessAccessTypeEnum.KW_TASK_PERMISSION_EXAMINER);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveKwExaminerListByTime(TimeRoomExaminerParam timeRoomExaminerParam) {
        String taskId = timeRoomExaminerParam.getTaskId();
        String timeId = timeRoomExaminerParam.getTimeId();
        // 0：判断编排数据是否锁定
        iTaskService.isNotLockDataThrowException(timeRoomExaminerParam.getTaskId());

        Set<String> newUserIdSet = new HashSet<>(timeRoomExaminerParam.getUserIds());
        // 1：考务人员基本信息kw_examiner表操作 考务和老师的关联
        List<Examiner> oldExaminerList = baseMapper.selectList(new LambdaQueryWrapper<Examiner>()
                .eq(Examiner::getTaskId, taskId)
        );
        Set<String> oldUserIdSet = oldExaminerList.stream().map(Examiner::getUserId).collect(Collectors.toSet());
        if (CollUtil.isEmpty(newUserIdSet) && CollUtil.isEmpty(oldUserIdSet)) {
            throw new KqException(ResponseCode.PARAM_USER_INFO_CAN_NOT_NULL.getCode(),
                    ResponseCode.PARAM_USER_INFO_CAN_NOT_NULL.getMsg());
        }
        // 差集
        //List<String> reduceUserIds = newUserIdSet.stream().filter(list -> !oldUserIdSet.contains(newUserIdSet)).collect(Collectors.toList());
        Set<String> reduceUserIds = new HashSet<>();
        reduceUserIds.addAll(newUserIdSet);
        reduceUserIds.removeAll(oldUserIdSet);
        // 批量添加kw_examiner表
        List<Examiner> examinerInsertList = new ArrayList<>();
        reduceUserIds.stream().forEach(uId -> {
            Examiner e = new Examiner();
            e.setTaskId(taskId);
            e.setUserId(uId);
            e.setType(UserRoleType.USER_ROLE_TYPE_PROCTOR.getCode());
            examinerInsertList.add(e);
        });

        if (CollUtil.isNotEmpty(examinerInsertList)) {
            saveBatch(examinerInsertList);
        }

        // 2：考务人员批次信息kw_time_examiner表操作 pi和老师的关联
        List<TimeExaminer> oldTimeExaminerList = iTimeExaminerService.getByALLByTime(taskId, timeId);
        Set<String> oldTimeUserIdSet = oldTimeExaminerList.stream().map(TimeExaminer::getUserId).collect(Collectors.toSet());
        // 交集
        //List<String> reduceTimeUserIds = newUserIdSet.stream().filter(list -> oldTimeUserIdSet.contains(newUserIdSet)).collect(Collectors.toList());
        // 差集，插入操作
        //List<String> reduceInsert = newUserIdSet.stream().filter(list -> !newUserIdSet.contains(oldTimeUserIdSet)).collect(Collectors.toList());
        reduceUserIds.clear();
        reduceUserIds.addAll(newUserIdSet);
        reduceUserIds.removeAll(oldTimeUserIdSet);
        List<TimeExaminer> timeExaminerInsertList = new ArrayList<>();
        reduceUserIds.stream().forEach(timeUserId -> {
            TimeExaminer timeExaminer = new TimeExaminer();
            timeExaminer.setTaskId(taskId);
            timeExaminer.setTimeId(timeId);
            timeExaminer.setUserId(timeUserId);
            examinerInsertList.stream().forEach(examiner -> {
                if (examiner.getUserId().equals(timeUserId)) {
                    timeExaminer.setExaminerId(examiner.getId());
                }
            });
            if (StringUtils.isEmpty(timeExaminer.getExaminerId())) {
                Set<Examiner> tempExaminer = oldExaminerList.stream().filter(examiner -> examiner.getUserId().equals(timeUserId)).collect(Collectors.toSet());
                tempExaminer.stream().forEach(exam -> {
                    timeExaminer.setExaminerId(exam.getId());
                });
            }
            timeExaminerInsertList.add(timeExaminer);
        });

        if (CollUtil.isNotEmpty(timeExaminerInsertList)) {
            iTimeExaminerService.insertByBatchByTime(timeExaminerInsertList);
        }
        // 差集，更新操作
        //List<String> reduceUpdate = newUserIdSet.stream().filter(list -> !oldTimeUserIdSet.contains(newUserIdSet)).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(newUserIdSet)) {
            iTimeExaminerService.lambdaUpdate()
                    .set(TimeExaminer::getDelFlag, false)
                    .eq(TimeExaminer::getTaskId, taskId)
                    .eq(TimeExaminer::getTimeId, timeId)
                    .in(true, TimeExaminer::getUserId, newUserIdSet)
                    .update();
            reduceUserIds.clear();
        } else {
            iTimeExaminerService.lambdaUpdate()
                    .set(TimeExaminer::getDelFlag, true)
                    .eq(TimeExaminer::getTaskId, taskId)
                    .eq(TimeExaminer::getTimeId, timeId)
                    .update();
            reduceUserIds.clear();
        }
        reduceUserIds.addAll(oldTimeUserIdSet);
        reduceUserIds.removeAll(newUserIdSet);
        if (CollUtil.isNotEmpty(reduceUserIds)) {
            iTimeExaminerService.lambdaUpdate()
                    .set(TimeExaminer::getDelFlag, true)
                    .eq(TimeExaminer::getTaskId, taskId)
                    .eq(TimeExaminer::getTimeId, timeId)
                    .in(true, TimeExaminer::getUserId, reduceUserIds)
                    .update();

            for (String userId : reduceUserIds) {
                TimeRoomExaminerVO timeRoomExaminerVO = new TimeRoomExaminerVO();
                timeRoomExaminerVO.setTaskId(taskId);
                timeRoomExaminerVO.setTimeId(timeId);
                timeRoomExaminerVO.setUserId(userId);
                // 1：删除kw_time_room_examiner表的考务人员考场设置信息
                iTimeRoomExaminerService.deleteAllByUserId(timeRoomExaminerVO);
            }

        }

        // 如果存在删除的监考员，需要清空删除监考员的考场信息

        // 3：同步权限平台修改用户角色信息
        if (CollUtil.isNotEmpty(newUserIdSet)) {
            // 设置监考员角色
            SetUsersRoleIdsParam param = new SetUsersRoleIdsParam();
            param.setRoleIds(Arrays.asList(UserRoleParam.USER_PROCTOR_ROLE_ID.getKey()));
            param.setOpraterType(UserRoleParam.USER_PROCTOR_ROLE_OPRATERTYPE_ADD.getKey());
            List<String> userIdsParam = newUserIdSet.stream().collect(Collectors.toList());
            param.setUserIds(userIdsParam);
            ApiResponse<Object> responseObject = iUaUserExtService.setUsersRoleids(param);
            //12001:成功；12286： 用户id不能为空;12287： 用户角色操作类型为空;12288： 用户角色为空; 12289： 设置机构用户角色失败
            if (!responseObject.getCode().equals(CodeEnum.UA_SUCCESS_CODE.getCode())) {
                throw new KqException(ResponseCode.ERROR_GET_POWER_USER.getCode(), "获取权限平台——修改机构用户角色接口返回异常：" + responseObject.getCode());
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateKwExaminerInfo(TimeRoomExaminerVO timeRoomExaminerVO) {
        // 0：判断编排数据是否锁定
        iTaskService.isNotLockDataThrowException(timeRoomExaminerVO.getTaskId());
        // 1：删除kw_time_room_examiner表的考务人员考场设置信息
        iTimeRoomExaminerService.deleteAllByUserId(timeRoomExaminerVO);
        // 2：批量添加新修改的考务人员考场设置信息
        List<OfficeRoom> officeRoomList = timeRoomExaminerVO.getRoomList();
        List<TimeRoomExaminer> timeRoomExaminerList = new ArrayList<>();
        officeRoomList.stream().forEach(officeRoom -> {
            TimeRoomExaminer timeRoomExaminer = new TimeRoomExaminer();
            String roomId = officeRoom.getId();
            timeRoomExaminer.setRoomId(roomId);
            timeRoomExaminer.setTaskId(timeRoomExaminerVO.getTaskId());
            timeRoomExaminer.setTimeId(timeRoomExaminerVO.getTimeId());
            timeRoomExaminer.setUserId(timeRoomExaminerVO.getUserId());
            timeRoomExaminer.setTimeExaminerId(timeRoomExaminerVO.getExaminerId());
            timeRoomExaminerList.add(timeRoomExaminer);
        });
        iTimeRoomExaminerService.insertByBatchByTimeId(timeRoomExaminerList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void resetKwExarminerPwd(ExaminerParam examinerParam) {
        // 1：根据用户id获取用户信息，调用平台端接口
        String userId = examinerParam.getUserId();
        final String newPwd = UserRoleParam.USER_PROCTOR_PWD_RESET.getKey();
        ApiResponse<Object> responseofficeUserResetPwd = iUaUserExtService.officeUserResetPwd(userId, newPwd);
        //12001：成功
        if (!responseofficeUserResetPwd.getCode().equals(CodeEnum.UA_SUCCESS_CODE.getCode())) {
            throw new KqException(ResponseCode.ERROR_GET_POWER_USER.getCode(), "权限平台重置密码接口返回异常：" + responseofficeUserResetPwd.getCode());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void examinerAllocation(ExaminerAllocationParam param) {
        //校验数据锁定状态
        iTaskService.isNotLockDataThrowException(param.getTaskId());
        //1.获取批次下的考务人员数据（批次考务人员id，考务人员id，用户id）
        List<TimeExaminer> timeExaminerList = iTimeExaminerService.getByTime(param.getTaskId(), param.getTimeId(),
                param.getExaminerType(), param.getExaminerIds());
        //2.获取批次下的考场信息
        List<RoomExaminerDTO> roomExaminerDTOList = iTimeRoomService.getRoomExaminerDTO(param.getTaskId(),
                param.getTimeId());
        //3.考务人员分配数据校验
        this.verifyAllocationData(timeExaminerList, roomExaminerDTOList);
        //4.将考务人员分配到考场中
        this.examinerAllocation(timeExaminerList, roomExaminerDTOList);
        //5.生成批次下的考务人员场次数据
        List<TimeRoomExaminer> timeRoomExaminerList = this.generateTimeRoomExaminer(roomExaminerDTOList,
                param.getTimeId(), param.getTaskId());
        //6.删除批次下的考务人员分配数据
        iTimeRoomExaminerService.deleteAllocatedByTimeId(param.getTaskId(), param.getTimeId());
        //7.保存考务人员分配数据
        this.saveTimeRoomExaminer(timeRoomExaminerList);
    }

    /**
     * 考务人员分配数据校验
     *
     * @param timeExaminerList    批次下的考务人员数据
     * @param roomExaminerDTOList 批次下的考场信息
     */
    private void verifyAllocationData(List<TimeExaminer> timeExaminerList,
                                      List<RoomExaminerDTO> roomExaminerDTOList) {
        //校验批次下的考务人员数据
        if (CollUtil.isEmpty(timeExaminerList)) {
            throw new KqException(ResponseCode.EXAMINER_NOT_FOUND_IN_TIME.getCode(),
                    ResponseCode.EXAMINER_NOT_FOUND_IN_TIME.getMsg());
        }
        //校验批次下的考场信息
        if (CollUtil.isEmpty(roomExaminerDTOList)) {
            throw new KqException(ResponseCode.ROOM_NOT_FOUND_IN_TIME.getCode(),
                    ResponseCode.ROOM_NOT_FOUND_IN_TIME.getMsg());
        }
    }

    /**
     * 将考务人员分配到考场中
     * 随机分配原则（尽量平均分配）：
     * 例1：当前批次考场数100个，考务人员50位，则每位考务人员分配2个考场
     * 例2：当前批次考场数50个，考务人员100位，则每个考场分配2位考务人员
     * 例3：当前批次考场数10个，考务人员3位，则前2位考务人员每人分配3个考场，最后1位考务人员分配4个考场
     * 例4：当前批次考场数3个，考务人员10位，则前2个考场分配3位考务人员，最后1个考场分配4位考务人员
     *
     * @param timeExaminerList    批次下所有考务人员数据
     * @param roomExaminerDTOList 批次下的考场信息
     */
    private void examinerAllocation(List<TimeExaminer> timeExaminerList,
                                    List<RoomExaminerDTO> roomExaminerDTOList) {
        if (timeExaminerList.size() >= roomExaminerDTOList.size()) {
            //考务人员比考场多，或考务人员与考场数量一致，获取到的是每个考场考务人员的数量，即一个考场会被分配多个不同的考务人员
            int[] parts = MathUtil.averageNumber(timeExaminerList.size(),
                    roomExaminerDTOList.size());
            //设置考场考务人员数量
            for (int i = 0; i < roomExaminerDTOList.size(); i++) {
                roomExaminerDTOList.get(i).setExaminerCount(parts[i]);
            }
            //将考务人员放入考场中
            loop:
            for (TimeExaminer timeExaminer : timeExaminerList) {
                for (RoomExaminerDTO roomExaminerDTO : roomExaminerDTOList) {
                    if (roomExaminerDTO.getTimeExaminerList().size() < roomExaminerDTO.getExaminerCount()) {
                        roomExaminerDTO.getTimeExaminerList().add(timeExaminer);
                        //继续遍历下一位考务人员
                        continue loop;
                    }
                }
            }
        } else {
            //考场比考务人员多，获取到的是每个考务人员分配到的考场数量，即一个考务人员会被分配多个不同的考场
            int[] parts = MathUtil.averageNumber(roomExaminerDTOList.size(),
                    timeExaminerList.size());
            //创建考务人员->考场数据结构
            List<ExaminerRoomDTO> examinerRoomDTOList = new ArrayList<>();
            for (int i = 0; i < timeExaminerList.size(); i++) {
                ExaminerRoomDTO examinerRoomDTO = new ExaminerRoomDTO();
                BeanUtils.copyProperties(timeExaminerList.get(i), examinerRoomDTO);
                examinerRoomDTO.setRoomCount(parts[i]);
                examinerRoomDTOList.add(examinerRoomDTO);
            }
            //将考场数据放入考务人员->考场数据结构中
            loop:
            for (RoomExaminerDTO roomExaminerDTO : roomExaminerDTOList) {
                for (ExaminerRoomDTO examinerRoomDTO : examinerRoomDTOList) {
                    if (examinerRoomDTO.getRoomIdList().size() < examinerRoomDTO.getRoomCount()) {
                        examinerRoomDTO.getRoomIdList().add(roomExaminerDTO.getRoomId());
                        //继续遍历下一个考场
                        continue loop;
                    }
                }
            }
            //【考务人员->考场】数据结构转换为【考场->考务人员】数据结构
            examinerRoomDTOList.forEach(examiner -> {
                List<String> roomIdList = examiner.getRoomIdList();
                roomExaminerDTOList.forEach(room -> {
                    if (roomIdList.contains(room.getRoomId())) {
                        room.getTimeExaminerList().add(examiner);
                    }
                });
            });
        }
    }

    /**
     * 生成批次下的考务人员场次数据
     *
     * @param roomExaminerDTOList 批次下的考场信息
     * @param timeId              批次id
     * @param taskId              考试任务id
     * @return 批次下的考务人员场次数据
     */
    private List<TimeRoomExaminer> generateTimeRoomExaminer(List<RoomExaminerDTO> roomExaminerDTOList,
                                                            String timeId, String taskId) {
        List<TimeRoomExaminer> timeRoomExaminerList = new ArrayList<>();
        //遍历每个考场
        roomExaminerDTOList.forEach(roomExaminerDTO -> {
            //合并考场内的考务人员数据
            List<TimeRoomExaminer> examinerList = roomExaminerDTO.getTimeExaminerList()
                    .stream()
                    .map(timeExaminer -> {
                        TimeRoomExaminer timeRoomExaminer = new TimeRoomExaminer();
                        timeRoomExaminer.setTaskId(taskId)
                                .setTimeId(timeId)
                                .setRoomId(roomExaminerDTO.getRoomId())
                                .setTimeExaminerId(timeExaminer.getId())
                                .setUserId(timeExaminer.getUserId());
                        return timeRoomExaminer;
                    }).collect(Collectors.toList());
            timeRoomExaminerList.addAll(examinerList);
        });
        return timeRoomExaminerList;
    }

    /**
     * 保存考务人员分配数据
     *
     * @param timeRoomExaminerList 考务人员分配数据
     */
    private void saveTimeRoomExaminer(List<TimeRoomExaminer> timeRoomExaminerList) {
        if (!iTimeRoomExaminerService.saveBatch(timeRoomExaminerList)) {
            throw new KqException(ResponseCode.EXAMINER_ALLOCATION_EXCEPTION.getCode(),
                    ResponseCode.EXAMINER_ALLOCATION_EXCEPTION.getMsg());
        }
    }

    @Override
    public void deleteByTask(String taskId) {
        QueryWrapper<Examiner> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Examiner::getTaskId, taskId);
        remove(queryWrapper);
    }

    @Override
    public void deleteAllByTask(String taskId) {
        //删除批次考务人员表
        iTimeExaminerService.deleteByTask(taskId);
        //删除考务人员分配结果表
        iTimeRoomExaminerService.deleteByTask(taskId);
    }

    /**
     * 获取机构部门树
     *
     * @param param
     * @return
     */
    @Override
    public List<Tree> getKwOrgTree(OrgTreeParamDTO param) {
        // 1：获取平台端全部部门
        ApiResponse<List<Tree>> responeObject = this.iUaDeptService.getKwDeptTree();
        if (!responeObject.getCode().equals(CodeEnum.UA_SUCCESS_CODE.getCode())) {
            throw new KqException(ResponseCode.ERROR_GET_POWER_USER.getCode(), "获取权限平台——查询部门树接口返回异常：" + responeObject.getCode());
        }
        List<Tree> treeList = responeObject.getData();
        return treeList;
    }

    /**
     * 获取机构人员
     *
     * @param pageParam
     * @param param
     * @return
     */
    @Override
    public Page<KwExaminerVO> getKwExaminer(Page<KwExaminerVO> pageParam, OrgTreeParamDTO param) {
        //1:分页对象
        Page<KwExaminerVO> page = new Page<>();
        // 2: 获取平台端全部用户，分页接口需要循环获取全部
        List<OfficeUserVO> deptUserList = getDeptUserListPage(pageParam, param, page);
        List<KwExaminerVO> userList = new ArrayList<>(deptUserList.size());
        deptUserList.stream().forEach(d -> {
            KwExaminerVO vo = new KwExaminerVO();
            vo.setUserId(d.getId());
            BeanUtils.copyProperties(d, vo);
            userList.add(vo);
            vo.setOrgName(d.getDeptName());
        });
        /*// 3：通过timeId查询同一批次下的所有设置的考务人员
        List<TimeExaminer> timeExaminerList = iTimeExaminerService.getByTime(param.getTaskId(), param.getTimeId(),
                UserRoleType.USER_ROLE_TYPE_PROCTOR.getCode(), "");
        Set<String> userIdSet = timeExaminerList.stream().map(TimeExaminer::getUserId).collect(Collectors.toSet());
        // 4：组装全部数据
        // 4.1 标记之前保存设置的考务人员，用于标记前端回显
        userList.stream().forEach(user -> {
            user.setIsShow(Boolean.FALSE);
            if (userIdSet.contains(user.getUserId())) {
                user.setIsShow(Boolean.TRUE);
            }
        });*/
        //组分页对象
        page.setCurrent(pageParam.getCurrent());
        page.setSize(pageParam.getSize());
        page.setRecords(userList);
        return page;
    }

    /**
     * @Description 获取平台端全部用户，需要循环获取用户数据（分页查询接口）
     * @Param
     * @Return List<OfficeUserVO>
     */
    private List<OfficeUserVO> getDeptUserListPage(Page<KwExaminerVO> pageParam, OrgTreeParamDTO param, Page<KwExaminerVO> page) {
        OfficeUserPageParam officeUserPageParam = new OfficeUserPageParam();
        int pageSize = (int) pageParam.getSize();
        int pageNo = (int) pageParam.getCurrent();

        officeUserPageParam.setStatus(true);
        officeUserPageParam.setCurrent(pageNo);
        officeUserPageParam.setSize(pageSize);
        officeUserPageParam.setUserName(param.getKeyWord());
        officeUserPageParam.setDeptId(param.getDeptId());
        officeUserPageParam.setRoleCode("OGT_OFFICE_PROCTOR");
        ApiResponse<Page<OfficeUserVO>> responseObject = iUaDeptService.getKwOfficeUserPage(officeUserPageParam);
        // 12001：成功；12281：查询机构用户分页异常; 12282：获取不到当前登录人信息;12283：当前查询的部门没有权限
        if (null == responseObject) {
            throw new KqException(ResponseCode.ERROR_GET_POWER_USER.getCode(), "获取权限平台——查询机构用户分页数据接口返回异常");
        }
        if (!CodeEnum.UA_SUCCESS_CODE.getCode().equals(responseObject.getCode())
                && !CodeEnum.UA_SUCCESS_CODE_V2.getCode().equals(responseObject.getCode())) {
            throw new KqException(ResponseCode.ERROR_GET_POWER_USER.getCode(), "获取权限平台——查询机构用户分页数据接口返回异常");
        }
        if (Objects.isNull(responseObject.getData())) {
            throw new KqException(ResponseCode.ERROR_GET_POWER_USER.getCode(), "获取权限平台——查询机构用户分页数据接口返回异常");
        }
        List<OfficeUserVO> deptUserListTemp = responseObject.getData().getRecords();
        page.setTotal(responseObject.getData().getTotal());
        return deptUserListTemp;
    }

    /**
     * 删除任务下监控人员
     *
     * @param taskId
     * @param userId
     * @param user
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteKwExaminer(String taskId, List<String> userId, User user) {
        if (CollectionUtils.isEmpty(userId)) {
            return Boolean.TRUE;
        }
        //先去判断是否存在绑定的监控员
        LambdaQueryWrapper<TimeRoomExaminer> query = Wrappers.lambdaQuery();
        query.eq(TimeRoomExaminer::getTaskId, taskId).eq(TimeRoomExaminer::getDelFlag, Boolean.FALSE);
        query.in(TimeRoomExaminer::getUserId, userId);
        query.select(TimeRoomExaminer::getUserId);
        List<TimeRoomExaminer> list = iTimeRoomExaminerService.list(query);
        Set<String> cantDelete = list.stream().map(TimeRoomExaminer::getUserId).collect(Collectors.toSet());
        if(!CollectionUtils.isEmpty(cantDelete)){
            //取名称用与前端提示
            QueryUsersParam params = new QueryUsersParam();
            params.setUserids(new ArrayList<>(cantDelete));
            ApiResponse<List<UserVO>> responseObject = this.iUaUserExtService.getUsersByIds(params);
            log.info("从平台获取机构监考员信息返回为:【{}】",responseObject);
            if (!responseObject.getCode().equals(CodeEnum.UA_SUCCESS_CODE.getCode())) {
                throw new KqException(ResponseCode.ERROR_GET_POWER_USER.getCode(), "获取监考员信息异常：" + responseObject.getCode());
            }
            List<UserVO> userVOList = responseObject.getData();
            StringBuilder sb = new StringBuilder();
            sb.append("监考员:");
            for(UserVO vo : userVOList){
                sb.append(vo.getUsername()).append(" ");
            }
            //用与前前提示
            throw new KqException(ResponseCode.ERROR_DELETE_EXAMINER_LOCK.getCode(),sb + ResponseCode.ERROR_DELETE_EXAMINER_LOCK.getMsg());
        }
        //差集
        Set<String> deletes = new HashSet<>(userId);
        deletes.removeAll(cantDelete);
        //没有需要删除的则直接返回
        if(CollectionUtils.isEmpty(deletes)){
            return Boolean.TRUE;
        }
        LambdaUpdateWrapper<Examiner> update = Wrappers.lambdaUpdate();
        update.eq(Examiner::getTaskId, taskId).in(Examiner::getUserId, deletes);
        update.set(Examiner::getDelFlag, Boolean.TRUE);
        Boolean result = this.update(update);
        iTaskService.saveTaskBusinessAccess(user,taskId,null,UserBusinessAccessTypeEnum.KW_TASK_PERMISSION_EXAMINER);
        return result;
    }

    @Override
    public void isExaminer(String taskId, List<String> userId, User currentUser){
        if (CollectionUtils.isEmpty(userId)) {
            return ;
        }
        LambdaQueryWrapper<Examiner> query = Wrappers.lambdaQuery();
        query.eq(Examiner::getTaskId, taskId).eq(Examiner::getDelFlag, Boolean.FALSE);
        query.in(Examiner::getUserId, userId);
        query.select(Examiner::getUserId);
        List<Examiner> list = examinerMapper.selectList(query);
        Set<String> cantDelete = list.stream().map(Examiner::getUserId).collect(Collectors.toSet());
        if(!CollectionUtils.isEmpty(cantDelete)){
            //用与前前提示
            throw new KqException(ResponseCode.ERROR_DELETE_EXAMINER_TASK.getCode(),ResponseCode.ERROR_DELETE_EXAMINER_TASK.getMsg());
        }
    }

    /**
     * 获取当前任务绑定的监考员userid
     * @param taskId
     * @return
     */
    @Override
    public List<String> queryTaskExaminer(String taskId){
        LambdaQueryWrapper<Examiner> query = Wrappers.lambdaQuery();
        query.eq(Examiner::getTaskId, taskId).eq(Examiner::getDelFlag, Boolean.FALSE);
        query.select(Examiner::getUserId);
        List<Examiner> examiners = baseMapper.selectList(query);
        List<String> userIds = examiners.stream().map(Examiner::getUserId).collect(Collectors.toList());
        return userIds;
    }

}
